class Observer {
  constructor(data) {
    this.walk(data);
  }
  // 1.遍历data所有属性
  walk(data) {
    // 加强程序健壮性，做对象判断
    if (!data || typeof data !== "object") return;
    Object.keys(data).forEach((key) => {
      this.defineReactive(data, key, data[key]);
    });
  }
  // 2.将data转换成响应式数据，即getter和setter
  // 特别说明：该方法中需要传入value而不直接使用data[key]的原因是 会造成循环引用的问题。
  defineReactive(data, key, value) {
    const that = this;
    // ______特别加入：为每一个属性增加Dep对象，负责收集依赖，发送通知。
    const dep = new Dep();
    // 特别情况1：当data的某一属性值也是对象时，也需要将其转换为getter和setter
    this.walk(value);
    Object.defineProperty(data, key, {
      configurable: true,
      enumerable: true,
      get() {
        // ______特别加入：在getter中收集观察者：
        // 判断是否有观察者的方式是在watcher类实例化时，向Dep类上挂载一个target属性，用于存储当前的watcher对象，在这里进行target判断，如果有，就使用dep.addSub()添加观察者。
        Dep.target && dep.addSub(Dep.target);
        return value;
      },
      set(newVal) {
        if (newVal === value) return;
        // 特别情况2：当设置data的某一个新属性值为对象时，也需要将其转换为getter和setter。
        // 由于这是在set方法中，this指向并非vue实例，故需要使用外面的that指向vue实例的对象。
        that.walk(newVal);
        value = newVal;
        // ____特别加入：在setter时，需要通知所有的观察者变化。
        dep.notify();
      },
    });
  }
}
